S3バケットのオブジェクト数やサイズを確認する前に知っておきたいこと(LISTリクエストとS3インベントリ)
こんにちは。DA事業本部の春田です。
年末の大掃除のように、たまに行いたいS3オブジェクトの棚卸し作業。AWS CLIを使って何も考えずにバケットの中身をチェックしてると、請求金額が結構お高くつきますよ、という注意書きです。
S3のLISTリクエスト
バケットの中身を確認する時、AWS CLIのaws s3 ls
というコマンドがよく使われますが、これの裏で動いているLISTリクエストの料金は、1,000リクエスト毎に0.0047USDかかります。1リクエストで取得できるオブジェクトの最大数は1,000件なので、0.0047USDで最大100万個のオブジェクトの情報を取得することができます。
気をつけなければいけないのは、S3に大量のオブジェクト、例えば1億個以上のオブジェクトに対して日次でLISTリクエストをかけている場合、月14.1USDも支払っていることになります。
大量のオブジェクトをLISTで取得するのは効率が悪いですし、何しろお金がもったいないです。データの棚卸しをしたい時は、S3インベントリがおすすめです。
S3インベントリ
S3インベントリは、バケット内のオブジェクト情報、メタデータなどを一挙に出力する機能です。CSVやORC、Parquetといった出力形式に対応しているので、Athenaからそのまま参照できます。なにより、LISTリクエストと比べて料金が安いです。こちらは100万個あたり0.0028USDなので、LISTリクエストのおおよそ半額ですね。
インベントリデータの出力先は別アカウントのバケットにも指定できるため、バケット間でオブジェクト情報を渡す時にも便利です。Glueのクローラを組み合わせれば、連携したいS3バケットのデータを自動でRedshiftにロードすることもできます。
(AWS Glue および Amazon Redshift を使用して Amazon S3 の利用料金を分析する | Amazon Web Services ブログから拝借)
ただし、日次または週次のスケジュール実行になるので、アドホックにインベントリデータを取得できません。オブジェクトの数にもよりますが、S3インベントリを設定して翌日ぐらいにならないとインベントリデータが出力されないのが難点ですね。そのため、S3の棚卸し作業を行う時は、事前に手順計画を立ててから行うことをおすすめします。
実際に使ってみた
S3インベントリの設定
今回のサンプルデータは、Registry of Open Data on AWSにてオープンデータとして提供されているCOVID-19 Data LakeのS3バケットのデータを使用します。2020年5月26日17時現在のオブジェクト数は約3万個でした。ちゃっかりaws s3 ls
を使ってますが悪しからず。
$ aws s3 ls s3://covid19-lake --recursive --human-readable --summarize 2020-03-25 04:56:58 0 Bytes alleninstitute/CORD19/comprehendmedical/ 2020-03-31 10:23:34 13.5 MiB alleninstitute/CORD19/comprehendmedical/comprehend_medical.json 2020-05-26 17:33:05 76.7 MiB alleninstitute/CORD19/json/metadata/part-00000-0cb5c32b-66b3-4002-b923-6f13be3723eb-c000.json 2020-03-21 02:13:06 0 Bytes alleninstitute/CORD19/raw/ 2020-03-29 01:25:22 71.3 KiB alleninstitute/CORD19/raw/biorxiv_medrxiv/0015023cc06b5362d332b3baf348d11567ca2fbb.json ... 2020-05-26 17:34:46 150.4 MiB tableau-covid-datahub/json/part-00000-95caaef8-a5c5-4de9-abac-fef109d7802d-c000.json 2020-05-26 12:39:54 179.5 MiB tableau-jhu/csv/COVID-19-Cases.csv 2020-05-21 20:38:58 80.0 MiB tableau-jhu/json/part-00000-0755f7e6-871b-4297-a4c3-c1f94ed3ebf1-c000.json 2020-05-21 20:39:01 80.1 MiB tableau-jhu/json/part-00001-0755f7e6-871b-4297-a4c3-c1f94ed3ebf1-c000.json 2020-05-21 20:38:57 55.5 MiB tableau-jhu/json/part-00002-0755f7e6-871b-4297-a4c3-c1f94ed3ebf1-c000.json Total Objects: 33840 Total Size: 37.8 GiB
インベントリの機能を使いたいので、自分の環境のバケットにsyncします。サイズ的に3時間くらい時間がかかりそうなので、EC2インスタンス上でnohupで実行しました。
$ aws s3 sync s3://covid19-lake s3://cm-haruta/covid19-lake/
対象のS3バケットに対してインベントリの設定を行います。まず、棚卸しをしたいソースバケットに入り、管理のタブを押下します。
インベントリを押下します。
他にインベントリがない場合は、以下の画面が表示されます。新規追加をクリックします。
インベントリ情報を入力していきます。フィルターはインベントリの対象としたいprefixを入力します。今回はcovid19-lake
配下のデータを対象としますが、バケット全体にしたい場合は空欄のままで大丈夫です。連携先バケットは、リージョンが同じであれば別アカウントのバケットも指定することができます。今回は同じバケットcm-haruta
のinventory
配下に出力させます。頻度は日別(日次)にします。
インベントリでは、全バージョンも含められたり、どのメタデータを抽出するかも事前に選択することができます。KMSと連携して暗号化も可能です。
インベントリが正常に作成されると、出力先に反映させるバケットポリシーのJSONを自動で表示してくれます。ソースバケットと出力先のバケットが異なる場合、書き込み用のバケットポリシーの設定もお忘れなく。
バケットポリシーはアクセス権限のタブから設定できます。既存のポリシーがなければ、先ほどのJSONをそのままコピペしてください。
これで準備完了です。インベントリ出力には時間がかかるので、一晩か二晩寝かせておきましょう。
AthenaからS3インベントリを参照する
2日後、期待したインベントリデータが作成されてました。
前節で設定したinventory/
配下に、バケット名と対象のprefixが続き、以下のようなディレクトリ構造でデータが作成されます。
inventory/cm-haruta/covid19-lake/ ├ 2020-05-25T00-00Z/ │ ├ manifest.checksum │ └ manifest.json -> 各種AWSサービスで使用できるインベントリデータのKeyやメタデータ ├ 2020-05-26T00-00Z/ │ └ ├ 2020-05-27T00-00Z/ │ └ ├ data/ │ ├ 2e99f2bd-0b34-4237-9c84-b208e2f8b1f6.parquet -> 25日分のインベントリデータ │ └ 9a53bd0c-9f1c-478b-90da-f5584a846d97.parquet -> 26日分のインベントリデータ └ hive/ ├ dt=2020-05-25-00-00/ │ └ symlink.txt -> Hive用の25日分のインベントリデータのKey ├ dt=2020-05-26-00-00/ │ └ └ dt=2020-05-27-00-00/ └
data/
配下に対して、AWS Glueのクローラをかけてスキーマ情報を取得します。最終的なクローラの設定は以下のような感じです。
クローラを実行して、作成されたテーブルは以下の通りです。データベース出力で設定したcm-haruta
に対して、Athenaからクエリをかけられるようになりました。
Athenaからプレビューして中身を見てみます。
SELECT * FROM "cm-haruta"."data";
カラム名 | データ例 |
---|---|
bucket | cm-haruta |
key | covid19-lake/alleninstitute/CORD19/comprehendmedical/comprehend_medical.json |
version_id | |
is_latest | TRUE |
is_delete_marker | FALSE |
size | 14136397 |
last_modified_date | 2020-05-26 07:27:51.000 |
インベントリを設定した時に選択したカラムは「サイズ」と「最終更新日」でしたので、それ以外はデフォルトで抽出される情報のようですね。過不足ないメタデータで使いやすそうです。
データの棚卸しができた完了したところで、prefixごとにサイズや最終更新日を以下のSQLで集計してみます。
WITH tidy AS ( SELECT CASE WHEN regexp_like(s3.key, '^covid19-lake/alleninstitute/') THEN 'alleninstitute' WHEN regexp_like(s3.key, '^covid19-lake/archived/') THEN 'archived' WHEN regexp_like(s3.key, '^covid19-lake/cfn/') THEN 'cfn' WHEN regexp_like(s3.key, '^covid19-lake/covid_knowledge_graph/') THEN 'covid_knowledge_graph' WHEN regexp_like(s3.key, '^covid19-lake/covidcast/') THEN 'covidcast' WHEN regexp_like(s3.key, '^covid19-lake/enigma-aggregation/') THEN 'enigma-aggregation' WHEN regexp_like(s3.key, '^covid19-lake/enigma-jhu-timeseries/') THEN 'enigma-jhu-timeseries' WHEN regexp_like(s3.key, '^covid19-lake/enigma-jhu/') THEN 'enigma-jhu' WHEN regexp_like(s3.key, '^covid19-lake/enigma-nytimes-data-in-usa/') THEN 'enigma-nytimes-data-in-usa' WHEN regexp_like(s3.key, '^covid19-lake/rearc-covid-19-nyt-data-in-usa/') THEN 'rearc-covid-19-nyt-data-in-usa' WHEN regexp_like(s3.key, '^covid19-lake/rearc-covid-19-prediction-models/') THEN 'rearc-covid-19-prediction-models' WHEN regexp_like(s3.key, '^covid19-lake/rearc-covid-19-testing-data/') THEN 'rearc-covid-19-testing-data' WHEN regexp_like(s3.key, '^covid19-lake/rearc-covid-19-world-cases-deaths-testing/') THEN 'rearc-covid-19-world-cases-deaths-testing' WHEN regexp_like(s3.key, '^covid19-lake/rearc-usa-hospital-beds/') THEN 'rearc-usa-hospital-beds' WHEN regexp_like(s3.key, '^covid19-lake/safegraph-open-census-data/') THEN 'safegraph-open-census-data' WHEN regexp_like(s3.key, '^covid19-lake/static-datasets/') THEN 'static-datasets' WHEN regexp_like(s3.key, '^covid19-lake/tableau-covid-datahub/') THEN 'tableau-covid-datahub' WHEN regexp_like(s3.key, '^covid19-lake/tableau-jhu/') THEN 'tableau-jhu' ELSE 'others' END AS key, s3.size, date_format(s3.last_modified_date, '%Y-%m-%d') AS last_modified_date FROM "cm-haruta"."data" AS s3 ) SELECT tidy.key, ROUND(CAST(SUM(tidy.size) AS DOUBLE) / 1024 / 1024 / 1024, 2) AS size_gb, MIN(tidy.last_modified_date) AS min_date, MAX(tidy.last_modified_date) AS max_date FROM tidy GROUP BY key ORDER BY key
key | size_gb | min_date | max_date |
---|---|---|---|
alleninstitute | 4.24 | 2020-05-26 | 2020-05-26 |
archived | 0.54 | 2020-05-26 | 2020-05-26 |
cfn | 0.0 | 2020-05-26 | 2020-05-26 |
covid_knowledge_graph | 1.14 | 2020-05-26 | 2020-05-26 |
covidcast | 4.12 | 2020-05-26 | 2020-05-26 |
enigma-aggregation | 0.03 | 2020-05-26 | 2020-05-26 |
enigma-jhu | 0.05 | 2020-05-26 | 2020-05-26 |
enigma-jhu-timeseries | 0.03 | 2020-05-26 | 2020-05-26 |
enigma-nytimes-data-in-usa | 0.02 | 2020-05-26 | 2020-05-26 |
others | 0.0 | 2020-05-26 | 2020-05-26 |
rearc-covid-19-nyt-data-in-usa | 0.02 | 2020-05-26 | 2020-05-26 |
rearc-covid-19-prediction-models | 0.01 | 2020-05-26 | 2020-05-26 |
rearc-covid-19-testing-data | 0.0 | 2020-05-26 | 2020-05-26 |
rearc-covid-19-world-cases-deaths-testing | 0.01 | 2020-05-26 | 2020-05-26 |
rearc-usa-hospital-beds | 0.0 | 2020-05-26 | 2020-05-26 |
safegraph-open-census-data | 27.01 | 2020-05-26 | 2020-05-26 |
static-datasets | 0.0 | 2020-05-26 | 2020-05-26 |
tableau-covid-datahub | 0.18 | 2020-05-26 | 2020-05-26 |
tableau-jhu | 0.39 | 2020-05-26 | 2020-05-26 |
第一階層ごとのオブジェクトサイズの合計と、最終変更日の最小値・最大値が取得できました。safegraph-open-census-data/
が容量食ってるようなので、ここにS3ライフサイクルポリシーを設定してあげると良さそうですね。
まとめ
aws s3 ls
コマンドを頻繁に使っている方、大量のオブジェクトに対してLISTリクエストをかけたい方は、S3インベントリの使用を検討してみてください。コスト効率がよく、GlueとAthenaを使えば簡単に集計用のSQLを叩くことができます。
参照
- Amazon S3 インベントリ - Amazon Simple Storage Service
- 料金 - Amazon S3 |AWS
- AWS Glue および Amazon Redshift を使用して Amazon S3 の利用料金を分析する | Amazon Web Services ブログ
- ls — AWS CLI 1.18.68 Command Reference
- 【AWS Black Belt Online Seminar】Amazon S3/Glacier - YouTube
- Registry of Open Data on AWS
- A public data lake for analysis of COVID-19 data | AWS Big Data Blog